//----------------------------------------------------------------------------------------------------
//
//	MailComposer
//
//	Inherits From:		Object
//
//	Declared In:		MailComposer.h
//
//	Disclaimer
//
//		You may freely copy, distribute and reuse this software and its
//		associated documentation. I disclaim any warranty of any kind, 
//		expressed or implied, as to its fitness for any particular use.
//
//----------------------------------------------------------------------------------------------------
#import "MailComposer.h"
#import "MailSpeaker.h"


@implementation MailComposer

//---------------------------------------------------------------------------------------------------------
//	Private Methods
//---------------------------------------------------------------------------------------------------------
- (BOOL)_setPort
{
	//  Should call this before any remote message to make sure Mail.app is
	//  running and mailSpeaker's port is current.  Get named port 'Mail'.  
	//  This will launch Mail.app if not already.  Get named port 'MailSendDemo'  
	//  (this is the one we will actually talk to).  Set mailSpeaker's port to be this one. 
	
    	port_t 	mailPort = NXPortFromName ("Mail", NULL);

	if (mailPort == PORT_NULL) 
		{
		(NXRunAlertPanel ("Accessing Mail", "Unable to connect to Mail.app",  
			NULL,  NULL, NULL));
		return NO;
		}
		
	mailPort = NXPortFromName ("MailSendDemo", NULL);

	if (mailPort == PORT_NULL) 
		{
		(NXRunAlertPanel ("Accessing Mail", "Unable to connect to Mail.app",  
			NULL,  NULL, NULL));
		return NO;
		}
		
    	[mailSpeaker setSendPort: mailPort];
	return YES;
}

	
- _nextText: sender
{
	//  This method attempts to help manage the UI flow, by moving to
	//  a TextField's nextText object when possible.  This is currently only possible
	//  by 'tabbing', but tabbing doesn't send an action.  This method will 
	//  allow an action to be sent and nextText to be selected when 'return' is
	//  entered.  Only works with TextFields and TextField subclasses.  Used by
	//  'takeFrom' methods.

	if ([sender isKindOf: [TextField class]]) 
		if ([[sender nextText] respondsTo: @selector(selectText:)])
			[[sender nextText] selectText:nil];

	return self;
}


//---------------------------------------------------------------------------------------------------------
//	Initializing and Freeing
//---------------------------------------------------------------------------------------------------------
- init
{
	[super init];
	mailSpeaker = [[MailSpeaker alloc] init];
	return self;
}


- free
{
	if (to)  free (to);
	if (subject)  free (subject);
	if (cc)  free (cc);
	if (body)  free (body);
	if (mailSpeaker) [mailSpeaker free];
	return [super free];
}

	
//---------------------------------------------------------------------------------------------------------
//	Accessor Methods
//---------------------------------------------------------------------------------------------------------
- (STR) to
{
	return to;
}

- (STR) subject
{
	return subject;
}

- (STR) cc
{
	return cc;
}

- (STR) body
{
	return body;
}

- to: (STR) aString
{
	if (! aString) return self;
	if (to)  free (to);
	to = NXCopyStringBuffer (aString);
	return self;
}

- subject: (STR) aString
{
	if (! aString) return self;
	if (subject)  free (subject);
	subject = NXCopyStringBuffer (aString);
	return self;
}

- cc: (STR) aString
{
	if (! aString) return self;
	if (cc)  free (cc);
	cc = NXCopyStringBuffer (aString);
	return self;
}

- body: (STR) aString
{
	if (! aString) return self;
	if (body)  free (body);
	body = NXCopyStringBuffer (aString);
	return self;
}


//---------------------------------------------------------------------------------------------------------
//	Action Methods
//---------------------------------------------------------------------------------------------------------
- takeToStringValueFrom: sender
{
	[self to: (STR)[sender stringValue]];
	[self _nextText: sender];
	return self;
}

- takeSubjectStringValueFrom: sender
{
	[self subject: (STR)[sender stringValue]];
	[self _nextText: sender];
	return self;
}

- takeCcStringValueFrom: sender
{
	[self cc: (STR)[sender stringValue]];
	[self _nextText: sender];
	return self;
}

- takeBodyStringValueFrom: sender
{
	[self body: (STR)[sender stringValue]];
	[self _nextText: sender];
	return self;
}

- takeRemoteToStringValueFrom: sender
{
	//  Set To: field in compose window using sender stringValue.
	
	if (! [self _setPort]) return nil;
	[mailSpeaker setTo: (STR)[sender stringValue]];
	[self _nextText: sender];
	return self;
}

- takeRemoteSubjectStringValueFrom: sender
{
	//  Set Subject: field in compose window using sender stringValue.
	
	if (! [self _setPort]) return nil;
	[mailSpeaker setSubject: (STR)[sender stringValue]];
	[self _nextText: sender];
	return self;
}

- takeRemoteCcStringValueFrom: sender
{
	//  Set Cc: field in compose window using sender stringValue.
	
	if (! [self _setPort]) return nil;
	[mailSpeaker setCc: (STR)[sender stringValue]];
	[self _nextText: sender];
	return self;
}

- takeRemoteBodyStringValueFrom: sender
{
	//  Set letter body in compose window using sender stringValue.
	
	if (! [self _setPort]) return nil;
	[mailSpeaker setBody: (STR)[sender stringValue]];
	[self _nextText: sender];
	return self;
}

- remoteOpen: sender
{
	//  Open a compose window in Mail.  Multiple calls to this method
	//  will open multiple windows.  However, all other methods will write
	//  to the 'oldest' open window.  For example , if 3 windows are opened,
	//  window 1 will be written to until it is closed/delivered, at that point 
	//  window 2 will be written to.  (Being a 'key' window has no affect
	//  on this ordering).
				
	if (! [self _setPort]) return nil;
	[mailSpeaker openSend];
	return self;
}

- remoteTo: sender
{
	//  Set To: field in compose window using instance variable.
	
	if (! [self _setPort]) return nil;
	if (to) [mailSpeaker setTo: to];
	return self;
}
	
- remoteSubject: sender
{
	//  Set Subject: field in compose window using instance variable.
	
	if (! [self _setPort]) return nil;
	if (subject) [mailSpeaker setSubject: subject];
	return self;
}
	
- remoteCc: sender
{
	//  Set Cc: field in compose window using instance variable.
	
	if (! [self _setPort]) return nil;
	if (cc) [mailSpeaker setCc: cc];
	return self;
}
	
- remoteBody: sender
{
	//  Set letter body in compose window using instance variable.
	
	if (! [self _setPort]) return nil;
	if (body) [mailSpeaker setBody: body];
	return self;
}
	
- remoteCompose: sender
{
	//  Sets all fields in compose window.  If a window  is not yet opened
	//  first remote call will open.  If a window already exists, this method will 
	//  overwrite its fields.
	
	[self remoteTo: nil];
	[self remoteSubject: nil];
	[self remoteCc: nil];
	[self remoteBody: nil];
	return self;
}

- remoteDeliver: sender
{
	//  Delivers the compose window.  If no window has been opened, 
	//  this method has no affect.  Mail.app will present an Alert panel if
	//  invalid 'To:' data exists in compose window.
	
	if (! [self _setPort]) return nil;
	[mailSpeaker deliver];
	return self;
}

- remoteComposeAndDeliver: sender
{
	//  Sets all fields in compose window and delivers.  If a window  is not yet 
	//  opened first remote call will open.  If a window already exists, this method 
	//  will overwrite its fields.  Mail.app will present an Alert panel if invalid 'To:'
	//  data exists in the compose window.

	[self remoteCompose: nil];
	[self remoteDeliver: nil];
	return self;
}


//---------------------------------------------------------------------------------------------------------
//	Archiving
//---------------------------------------------------------------------------------------------------------
- read: (NXTypedStream*) aStream
{
    [super read: aStream];
    NXReadTypes (aStream, "@****", &mailSpeaker, &to, &subject, &cc, &body);
    return self;
}

- write: (NXTypedStream*) aStream
{
    [super write: aStream];
    NXWriteTypes (aStream, "@****", &mailSpeaker, &to, &subject, &cc, &body);
    return self;
}


//---------------------------------------------------------------------------------------------------------
//	IB Methods
//---------------------------------------------------------------------------------------------------------
- (const char *)getInspectorClassName
{
	//  This returns the name of the class responsible for managing a custom 
	//  IB Attributes inspector.
		
    	return "MailComposerInspector";
}

- (NXImage*) getIBImage
{
	//  This returns the NXImage instance that will be displayed in IB's File Viewer
	//  when this class is instantiated.

	return [NXImage findImageNamed: "MailComposerIcon"];
}


@end